package com.ljy.kotlindemo

import android.os.Build
import androidx.annotation.RequiresApi
import java.util.*
import kotlin.collections.HashMap
import kotlin.collections.HashSet
import kotlin.math.sign

/**
 * @Author:         LiuJinYang
 * @CreateDate:     2020/10/15
 * 集合
 */


fun main() {
    //测试Collection
    testCollection()
    //测试MutableCollection
    testMutableCollection()
    //测试list
    testList()
    //测试MutableList
    testMutableList()
    //测试set
    testSet()
    //测试MutableSet
    testMutableSet()
    //测试map
    testMap()
    //测试MutableMap
    testMutableMap()
    //测试构造集合
    testConstructor()
    //测试迭代器
    testIterable()
    //测试区间与数列
    testRange()
    //测试序列
    testSequence()
    //测试操作
    testOperation()
    //测试转换
    testTransform()
    //测试过滤
    testFilter()
    //测试加减操作符
    testPlusMinus()
    //测试分组
    testGroup()
    //取集合的一部分
    testPart()
    //取单个元素
    testGetOne()
    //集合排序
    testShort()
    //聚合操作
    testArithmetic()
    //集合写操作
    testWrite()
    //list&set相关操作
    testList1()
    //map相关操作
    testMap11()
}
//一。 集合概述
//Kotlin 标准库提供了基本集合类型的实现： set、list 以及 map。 一对接口代表每种集合类型：
//
//一个 只读 接口，提供访问集合元素的操作。
//一个 可变 接口，通过写操作扩展相应的只读接口：添加、删除和更新其元素。

//Collection<T> 是集合层次结构的根。此接口表示一个只读集合的共同行为：检索大小、检测是否为成员等等。
//public interface Collection<out E> : Iterable<E>
// Collection 继承自 Iterable <T> 接口，它定义了迭代元素的操作。
//对于更具体的情况，请使用 Collection 的继承者： List 与 Set。
fun testCollection() {
    val stringList = listOf("111", "222", "111", "333")
    printAll(stringList)
    val stringSet = setOf("aaa", "bbb", "aaa", "ccc")
    printAll(stringSet)
}

fun printAll(strings: Collection<String>) {
    for (s in strings)
        print("$s , ")
    println()
}

//MutableCollection 是一个具有写操作的 Collection 接口，例如 add 以及 remove。
//public interface MutableCollection<E> : Collection<E>, MutableIterable<E>
fun testMutableCollection() {
    val words = "A long time ago in a galaxy far far away".split(" ")
    val shortWords = mutableListOf<String>()
    words.getShortWords(shortWords, 3)
    println(shortWords)
}

fun List<String>.getShortWords(shortWords: MutableList<String>, maxLength: Int) {
    this.filterTo(shortWords) { it.length <= maxLength }
    val articles = setOf("a", "A", "an", "An", "the", "The")
    shortWords -= articles
}

//List<T> 以指定的顺序存储元素，并提供使用索引访问元素的方法。索引从 0 开始 – 第一个元素的索引 – 直到 最后一个元素的索引 即 (list.size - 1)。
fun testList() {
    val numbers = listOf("one", "two", "three", "four")
    println("Number of elements: ${numbers.size}")
    println("Third element: ${numbers.get(2)}")
    println("last element: ${numbers[numbers.lastIndex]}")
    println("Index of element \"two\": ${numbers.indexOf("two")}")
    //List 元素（包括空值）可以重复：List 可以包含任意数量的相同对象或单个对象的出现。
    // 如果两个 List 在相同的位置具有相同大小和相同结构的元素，则认为它们是相等的。
    val bob = Person("Bob", 31)
    val people = listOf(Person("Adam", 20), bob, bob)
    val people2 = listOf(Person("Adam", 20), Person("Bob", 31), bob)
    println(people == people2)
    println(people === people2)
    bob.age = 32
    println(people == people2)
    println(people === people2)
}

data class Person(var name: String?, var age: Int?)

//MutableList<T> 是可以进行写操作的 List，例如用于在特定位置添加或删除元素
//在 Kotlin 中，List 的默认实现是 ArrayList，可以将其视为可调整大小的数组。
fun testMutableList() {
    val numbers = mutableListOf(1, 2, 3, 4)
    println(numbers)
    numbers.add(5)
    println(numbers)
    numbers.removeAt(1)
    println(numbers)
    numbers[0] = 0
    println(numbers)
    numbers.shuffle()
    println(numbers)
}

//Set<T> 存储唯一的元素；它们的顺序通常是未定义的。null 元素也是唯一的：一个 Set 只能包含一个 null。
// 当两个 set 具有相同的大小并且对于一个 set 中的每个元素都能在另一个 set 中存在相同元素，则两个 set 相等。
fun testSet() {
    val numbers = setOf(1, 2, 3, 4)
    println("Number of elements: ${numbers.size}")
    if (numbers.contains(1)) println("1 is in the set")

    val numbersBackwards = setOf(4, 3, 2, 1)
    println("The sets are equal: ${numbers == numbersBackwards}")
}

//MutableSet 是一个带有来自 MutableCollection 的写操作接口的 Set。
//Set的默认实现 - LinkedHashSet – 保留元素插入的顺序。 因此，依赖于顺序的函数，
// 例如 first() 或 last()，会在这些 set 上返回可预测的结果。
fun testMutableSet() {
    val numbers = setOf(1, 2, 3, 4)  // LinkedHashSet is the default implementation
    val numbersBackwards = setOf(4, 3, 2, 1)

    println(numbers.first() == numbersBackwards.first())
    println(numbers.first() == numbersBackwards.last())
}
//另一种实现方式 – HashSet – 不声明元素的顺序，所以在它上面调用这些函数会返回不可预测的结果。
// 但是，HashSet 只需要较少的内存来存储相同数量的元素

// Map<K, V> 不是 Collection 接口的继承者；但是它也是 Kotlin 的一种集合类型。
// Map 存储 键-值 对（或 条目）；键是唯一的，但是不同的键可以与相同的值配对。
// Map 接口提供特定的函数进行通过键访问值、搜索键和值等操作。
fun testMap() {
    val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)
    println("All keys: ${numbersMap.keys}")
    println("All values: ${numbersMap.values}")
    if ("key2" in numbersMap) println("Value by key \"key2\": ${numbersMap["key2"]}")
    if (1 in numbersMap.values) println("The value 1 is in the map")
    if (numbersMap.containsValue(1)) println("The value 1 is in the map") // 同上
    //无论键值对的顺序如何，包含相同键值对的两个 Map 是相等的
    val anotherMap = mapOf("key2" to 2, "key1" to 1, "key4" to 1, "key3" to 3)

    println("The maps are equal: ${numbersMap == anotherMap}")
}

//MutableMap 是一个具有写操作的 Map 接口，可以使用该接口添加一个新的键值对或更新给定键的值。
//Map 的默认实现 – LinkedHashMap – 迭代 Map 时保留元素插入的顺序。 反之，另一种实现 – HashMap – 不声明元素的顺序。
fun testMutableMap() {
    val numbersMap = mutableMapOf("one" to 1, "two" to 2)
    numbersMap.put("three", 3)
    numbersMap.put("two", 22)
    numbersMap["one"] = 11
    println(numbersMap)
}

//二。构造集合
fun testConstructor() {
    //1. 由元素构造
    //创建集合的最常用方法是使用标准库函数 listOf<T>()、setOf<T>()、mutableListOf<T>()、mutableSetOf<T>()。
    // 如果以逗号分隔的集合元素列表作为参数，编译器会自动检测元素类型。创建空集合时，须明确指定类型。
    val numberSet = setOf("111", "222", "333")
    println(numberSet)
    val emptySet = mutableSetOf<String>()
    println(emptySet)
    //Map 也有这样的函数 mapOf() 与 mutableMapOf()。映射的键和值作为 Pair 对象传递（通常使用中缀函数 to 创建）
    val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)
    println(numbersMap)
    //注意，to 符号创建了一个短时存活的 Pair 对象，因此建议仅在性能不重要时才使用它。
    // 为避免过多的内存使用，请使用其他方法。
    // 例如，可以创建可写 Map 并使用写入操作填充它。 apply() 函数可以帮助保持初始化流畅。
    val numbersMap2 = mutableMapOf<String, String>().apply { this["one"] = "1"; this["two"] = "2" }
    println(numbersMap2)
    //2. 空集合
    //还有用于创建没有任何元素的集合的函数：emptyList()、emptySet() 与 emptyMap()。 创建空集合时，应指定集合将包含的元素类型。
    val emptyList = emptyList<String>()
    //3. list 的初始化函数
    //对于 List，有一个接受 List 的大小与初始化函数的构造函数，该初始化函数根据索引定义元素的值。
    val doubled = List(5, { it * 2 })  // 如果你想操作这个集合，应使用 MutableList
    println(doubled)
    //4. 具体类型构造函数
    //要创建具体类型的集合，例如 ArrayList 或 LinkedList，可以使用这些类型的构造函数。 类似的构造函数对于 Set 与 Map 的各实现中均有提供。
    val linkedList = LinkedList<String>(listOf("one", "two", "three"))
    val presizedSet = HashSet<Int>(32)
    val hashMap = HashMap<String, Int>()
    //5. 复制
    //在特定时刻通过集合复制函数，例如toList()、toMutableList()、toSet() 等等。创建了集合的快照。
    // 结果是创建了一个具有相同元素的新集合 如果在源集合中添加或删除元素，则不会影响副本。副本也可以独立于源集合进行更改。
    val sourceList = mutableListOf(1, 2, 3)
    val copyList = sourceList.toMutableList()
    val readOnlyCopyList = sourceList.toList()
    sourceList.add(4)
    println("Copy size: ${copyList.size}")
    //readOnlyCopyList.add(4)             // 编译异常
    println("Read-only copy size: ${readOnlyCopyList.size}")
    //这些函数还可用于将集合转换为其他类型，例如根据 List 构建 Set，反之亦然
    val copySet = sourceList.toMutableSet()
    copySet.add(3)
    copySet.add(4)
    println(copySet)
    //可以创建对同一集合实例的新引用。使用现有集合初始化集合变量时，将创建新引用。 因此，当通过引用更改集合实例时，更改将反映在其所有引用中。
    val referenceList = sourceList
    referenceList.add(4)
    println("Source size: ${sourceList.size}")
    //集合的初始化可用于限制其可变性。例如，如果构建了一个 MutableList 的 List 引用，当你试图通过此引用修改集合的时候，编译器会抛出错误
    val referenceList2: List<Int> = sourceList
    //referenceList.add(4)            // 编译错误
    sourceList.add(4)
    println(referenceList2) // 显示 sourceList 当前状态
    //6. 调用其他集合的函数
    //可以通过其他集合各种操作的结果来创建集合。例如，过滤列表会创建与过滤器匹配的新元素列表：
    val numbers = listOf("one", "two", "three", "four")
    val longerThan3 = numbers.filter { it.length > 3 }
    println(longerThan3)
    //映射生成转换结果列表：
    val numbers2 = setOf(1, 2, 3)
    println(numbers2.map { it * 3 })
    println(numbers2.mapIndexed { idx, value -> value * idx })
    //关联生成 Map:
    val numbers3 = listOf("one", "two", "three", "four")
    println(numbers3.associateWith { it.length })
}

//三。迭代器
fun testIterable() {
    val numbers = listOf("111", "222", "333", "444")
    //1. Iterable<T> 接口的继承者（包括 Set 与 List）可以通过调用 iterator() 函数获得迭代器
    //一旦迭代器通过了最后一个元素，它就不能再用于检索元素；也无法重新指向到以前的任何位置。要再次遍历集合，请创建一个新的迭代器。
    val numbersIterator = numbers.listIterator()
    while (numbersIterator.hasNext()) {
        println("listIterator:${numbersIterator.next()}")
    }
    //2. for循环
    for (it in numbers) {
        println("for: $it")
    }
    //3. forEach
    numbers.forEach {
        println("forEach: $it")
    }
    //4. List 迭代器
    //对于列表，有一个特殊的迭代器实现：
    // ListIterator 它支持列表双向迭代：正向与反向。 反向迭代由 hasPrevious() 和 previous() 函数实现。
    // 此外， ListIterator 通过 nextIndex() 与 previousIndex() 函数提供有关元素索引的信息。
    val listIterator = numbers.listIterator()
    while (listIterator.hasNext()) {
        print("next_1: Index: ${listIterator.nextIndex()}")
        println(", value: ${listIterator.next()}")
    }
    while (listIterator.hasNext()) {
        print("next_2: Index: ${listIterator.nextIndex()}")
        println(", value: ${listIterator.next()}")
    }
    println("Iterating backwards:")
    while (listIterator.hasPrevious()) {
        print("previous: Index: ${listIterator.previousIndex()}")
        println(", value: ${listIterator.previous()}")
    }
    //具有双向迭代的能力意味着 ListIterator 在到达最后一个元素后仍可以使用。
    while (listIterator.hasNext()) {
        print("next_3: Index: ${listIterator.nextIndex()}")
        println(", value: ${listIterator.next()}")
    }
    //5.可变迭代器
    //为了迭代可变集合，于是有了 MutableIterator 来扩展 Iterator 使其具有元素删除函数 remove() 。
    // 因此，可以在迭代时从集合中删除元素。
    val numbers2 = mutableListOf("aaa", "bbb", "ccc", "ddd")
    var numbers2Iterator = numbers2.iterator()
    println(numbers2Iterator.next())
    println(numbers2Iterator.remove())
    println("after remove: $numbers2")
    //除了删除元素， MutableListIterator 还可以在迭代列表时插入和替换元素。
    numbers2Iterator = numbers2.listIterator()
    numbers2Iterator.next()
    numbers2Iterator.add("two")
    numbers2Iterator.next()
    numbers2Iterator.set("three")
    println(numbers2)
}

//四。区间与数列
fun testRange() {
    //1. Kotlin 可通过调用 kotlin.ranges 包中的 rangeTo() 函数及其操作符形式的 .. 轻松地创建两个值的区间。 通常，rangeTo() 会辅以 in 或 !in 函数。
    for (i in 1.rangeTo(6)) {
        print(i)
    }
    println()
    for (i in 1..7) {
        print(i)
    }
    println()
    //要反向迭代数字，请使用 downTo 函数而不是 ..
    for (i in 8 downTo 1) {
        print(i)
    }
    println()
    //也可以通过任意步长（不一定为 1 ）迭代数字
    for (i in 1..9 step 2)
        print(i)
    println()
    //要迭代不包含其结束元素的数字区间，请使用 until 函数
    for (i in 1 until 10)
        print(i)
    println()
    //2. 区间
    //区间从数学意义上定义了一个封闭的间隔：它由两个端点值定义，这两个端点值都包含在该区间内。
    // 区间是为可比较类型定义的：具有顺序，可以定义任意实例是否在两个给定实例之间的区间内。
    //要为类创建一个区间，请在区间起始值上调用 rangeTo() 函数，并提供结束值作为参数。 rangeTo() 通常以操作符 .. 形式调用。
//    val versionRange=Version(1,10).rangeTo(Version(1,30))
    val versionRange = Version(1, 10)..Version(1, 30)
    println(Version(0, 9) in versionRange)
    println(Version(1, 22) in versionRange)
    //3. 数列


}

class Version(val major: Int, val minor: Int) : Comparable<Version> {
    override fun compareTo(other: Version): Int {
        if (this.major != other.major) {
            return this.major - other.major
        }
        return this.minor - other.minor
    }
}

//五。序列
fun testSequence() {
    //1. 除了集合之外，Kotlin 标准库还包含另一种容器类型——序列（Sequence<T>）。
    // 序列提供与 Iterable 相同的函数，但实现另一种方法来进行多步骤集合处理
    //当 Iterable 的处理包含多个步骤时，它们会优先执行：每个处理步骤完成并返回其结果——中间集合。
    // 在此集合上执行以下步骤。反过来，序列的多步处理在可能的情况下会延迟执行：仅当请求整个处理链的结果时才进行实际计算。
    //操作执行的顺序也不同：Sequence 对每个元素逐个执行所有处理步骤。 反过来，Iterable 完成整个集合的每个步骤，然后进行下一步。
    //因此，这些序列可避免生成中间步骤的结果，从而提高了整个集合处理链的性能。 但是，序列的延迟性质增加了一些开销，
    // 这些开销在处理较小的集合或进行更简单的计算时可能很重要。 因此，应该同时考虑使用 Sequence 与 Iterable，并确定在哪种情况更适合。
    //2. 构造序列
    //由元素
    val numbersSequence = sequenceOf("444", "333", "222", "111")
    //由 Iterable
    val numbers = listOf("111", "222", "333", "444")
    val numbersSequence2 = numbers.asSequence()
    //由函数
    //可以将第一个元素指定为显式值或函数调用的结果。 当提供的函数返回 null 时，序列生成停止。因此，以下示例中的序列是无限的。
    val oddNumbers = generateSequence(2) { it + 2 } // `it` 是上一个元素
    println(oddNumbers.take(5).toList())
    //println(oddNumbers.count())     // 错误：此序列是无限的。
    //要使用 generateSequence() 创建有限序列，请提供一个函数，该函数在需要的最后一个元素之后返回 null。
    val oddNumbersLessThan10 = generateSequence(1) { if (it + 2 < 10) it + 2 else null }
    println(oddNumbersLessThan10.count())
    println(oddNumbersLessThan10.toList())
    //由组块
    //有一个函数可以逐个或按任意大小的组块生成序列元素——sequence() 函数。 此函数采用一个 lambda 表达式，
    // 其中包含 yield() 与 yieldAll() 函数的调用。 它们将一个元素返回给序列使用者，并暂停 sequence() 的执行，
    // 直到使用者请求下一个元素。 yield() 使用单个元素作为参数；yieldAll() 中可以采用 Iterable 对象、Iterable 或其他 Sequence。
    // yieldAll() 的 Sequence 参数可以是无限的。 当然，这样的调用必须是最后一个：之后的所有调用都永远不会执行
    val oddNumbers2 = sequence {
        yield(1)
        yieldAll(listOf(3, 5))
        yieldAll(generateSequence(7) { it + 2 })
    }
    println(oddNumbers2.take(5).toList())
    //3. 序列操作
    //我们通过一个示例来看 Iterable 与 Sequence 之间的区别。
    //
    //Iterable
    val words = "The quick brown fox jumps over the lazy dog".split(" ")
    val lengthsList = words.filter { println("filter:$it");it.length > 3 }
        .map { println("length:${it.length}");it.length }
        .take(4)
    println("Lengths of first 4 words longer than 3 chars:")
    println(lengthsList)
    //Sequence
    // 将列表转换为序列
    val wordsSequence = words.asSequence()
    val lengthsSequence = wordsSequence.filter { println("filter: $it"); it.length > 3 }
        .map { println("length: ${it.length}"); it.length }
        .take(4)

    println("Lengths of first 4 words longer than 3 chars")
    // 末端操作：以列表形式获取结果。
    println(lengthsSequence.toList())
}

//六。操作概述
fun testOperation() {
    //集合操作在标准库中以两种方式声明：集合接口的成员函数和扩展函数
    //成员函数定义了对于集合类型是必不可少的操作
    //其他集合操作被声明为扩展函数。这些是过滤、转换、排序和其他集合处理功能。
    //操作将返回其结果，而不会影响原始集合
    val numbers = listOf("one", "two", "three", "three", "three", "four")
    numbers.filter { it.length > 3 }  // `numbers` 没有任何改变，结果丢失
    println("numbers are still $numbers")
    val longerThan3 = numbers.filter { it.length > 3 } // 结果存储在 `longerThan3` 中
    println("numbers longer than 3 chars are $longerThan3")
    //对于某些集合操作，有一个选项可以指定 目标 对象。 目标是一个可变集合，该函数将其结果项附加到该可变对象中，而不是在新对象中返回它们
    // 对于执行带有目标的操作，有单独的函数，其名称中带有 To 后缀，例如，用 filterTo() 代替 filter()
    val filterResults = mutableListOf<String>()  // 目标对象
    numbers.filterTo(filterResults) { it.length > 3 }
    numbers.filterIndexedTo(filterResults) { index, _ -> index == 0 }
    println(filterResults) // 包含两个操作的结果
    //为了方便起见，这些函数将目标集合返回了，因此您可以在函数调用的相应参数中直接创建它
    // 将数字直接过滤到新的哈希集中，从而消除结果中的重复项
    val result = numbers.mapTo(HashSet()) { it }
    val result2 = numbers.mapTo(HashSet()) { it.length }
    println("distinct item are $result")
    println("distinct item lengths are $result2")
    //写操作
    //对于可变集合，还存在可更改集合状态的 写操作 。这些操作包括添加、删除和更新元素
    //对于某些操作，有成对的函数可以执行相同的操作：一个函数就地应用该操作，另一个函数将结果作为单独的集合返回。
    // 例如， sort() 就地对可变集合进行排序，因此其状态发生了变化； sorted() 创建一个新集合，该集合包含按排序顺序相同的元素。
    val numbers2 = mutableListOf("one", "two", "three", "four")
    println("numbers2:$numbers2")
    val sortedNumbers = numbers2.sorted()
    println("sortedNumbers:$sortedNumbers")
    println(numbers2 == sortedNumbers)  // false
    println("numbers2:$numbers2")
    numbers2.sort()
    println("numbers2:$numbers2")
    println(numbers2 == sortedNumbers)  // true
}

//七。集合转换
fun testTransform() {
    //1. 映射 map
    //映射 转换从另一个集合的元素上的函数结果创建一个集合。 基本的映射函数是 map()。
    // 它将给定的 lambda 函数应用于每个后续元素，并返回 lambda 结果列表。 结果的顺序与元素的原始顺序相同。
    // 如需应用还要用到元素索引作为参数的转换，请使用 mapIndexed()。
    val numbers = setOf(11, 22, 33, 44, 55)
    println(numbers.map { it * 2 })
    println(numbers.mapIndexed { index, value -> value * 100 + index })
    //如果转换在某些元素上产生 null 值，则可以通过调用 mapNotNull() 函数取代 map() 或 mapIndexedNotNull() 取代 mapIndexed() 来从结果集中过滤掉 null 值
    println(numbers.mapNotNull { if (it % 2 == 0) null else it * 3 })
    println(numbers.mapIndexedNotNull { idx, value -> if (idx == 0) null else value * idx })
    //映射转换时，有两个选择：转换键，使值保持不变，反之亦然。 要将指定转换应用于键，请使用 mapKeys()；
    // 反过来，mapValues() 转换值。 这两个函数都使用将映射条目作为参数的转换，因此可以操作其键与值
    val numbersMap = mapOf("key1" to 11, "key2" to 22, "key3" to 33, "key4" to 44)
    println(numbersMap.mapKeys { it.key.toUpperCase() })
    println(numbersMap.mapValues { it.value * 100 + it.key.length })
    //2. 双路合并 zip
    //双路合并 转换是根据两个集合中具有相同位置的元素构建配对
    //如果集合的大小不同，则 zip() 的结果为较小集合的大小；结果中不包含较大集合的后续元素
    val colors = listOf("red", "green", "blue")
    val animals = listOf("fox", "bear", "dog", "cat")
    val result = colors zip animals
    println(result)
    //也可以使用带有两个参数的转换函数来调用 zip()：接收者元素和参数元素
    //在这种情况下，结果 List 包含在具有相同位置的接收者对 和 参数元素对 上调用的 转换函数的 返回值。
    val result2 = colors.zip(animals) { color, animal -> "The ${animal.capitalize()} is $color" }
    println(result2)
    //当拥有 Pair 的 List 时，可以进行反向转换 unzipping——从这些键值对中构建两个列表：
    val unzip1 = result.unzip()
    println(unzip1)
    //3. 关联  associateWith
    //关联 转换允许从集合元素和与其关联的某些值构建 Map
    println(animals.associateWith { it.length })
    println(animals.associateBy { it.first().toUpperCase() })
    println(
        animals.associateBy(
            keySelector = { it.first().toUpperCase() },
            valueTransform = { it.length })
    )
    val names = listOf("Alice Adams", "Brian Brown", "Clara Campbell")
    println(names.associate { name -> parseFullName(name).let { it.lastName to it.firstName } })
    //4. 打平
    //如需操作嵌套的集合，则可能会发现提供对嵌套集合元素进行打平访问的标准库函数很有用
    // flatten()。可以在一个集合的集合（例如，一个 Set 组成的 List）上调用它。 该函数返回嵌套集合中的所有元素的一个 List
    val numberSets = listOf(setOf(1, 2, 3), setOf(4, 5), setOf(1, 2))
    println(numberSets.flatten())
    //flatMap() 提供了一种灵活的方式来处理嵌套的集合。 它需要一个函数将一个集合元素映射到另一个集合。
    // 因此，flatMap() 返回单个列表其中包含所有元素的值。 所以，flatMap() 表现为 map()（以集合作为映射结果）与 flatten() 的连续调用。
    println(numberSets.flatMap { it })

    val containers = listOf(
        StringContainer(listOf("one", "two", "three")),
        StringContainer(listOf("four", "five", "six")),
        StringContainer(listOf("seven", "eight"))
    )
    println(containers)
    println(containers.flatMap { it.values })

    //5. 字符串表示
    //如果需要以可读格式检索集合内容，请使用将集合转换为字符串的函数：joinToString() 与 joinTo()。
    //joinToString() 根据提供的参数从集合元素构建单个 String。 joinTo() 执行相同的操作，但将结果附加到给定的 Appendable 对象
    println(animals.joinToString())
    val listString = StringBuffer("The list of animals: ")
    animals.joinTo(listString)
    println(listString)
    //要构建自定义字符串表示形式，可以在函数参数 separator、prefix 与 postfix中指定其参数。
    // 结果字符串将以 prefix 开头，以 postfix 结尾。除最后一个元素外，separator 将位于每个元素之后。
    println(animals.joinToString(separator = " | ", prefix = "start: ", postfix = " :end"))
    //对于较大的集合，可能需要指定 limit ——将包含在结果中元素的数量。
    // 如果集合大小超出 limit，所有其他元素将被 truncated 参数的单个值替换
    val nums = (1..100).toList()
    println(nums.joinToString(limit = 10, truncated = "<...>"))
    //要自定义元素本身的表示形式，请提供 transform 函数。
    println(animals.joinToString { "Element: ${it.toUpperCase()}" })

}

data class StringContainer(val values: List<String>)

fun parseFullName(fullName: String): FullName {
    val nameParts = fullName.split(" ")
    if (nameParts.size == 2) {
        return FullName(nameParts[0], nameParts[1])
    } else throw Exception("Wrong name format")
}

data class FullName(val firstName: String, val lastName: String)

//八。过滤
fun testFilter() {
    //1. 过滤是最常用的集合处理任务之一。在Kotlin中，过滤条件由 谓词 定义——接受一个集合元素并且返回
    // 布尔值的 lambda 表达式：true 说明给定元素与谓词匹配，false 则表示不匹配。
    val animals = listOf("fox", "bear", "dog", "cat")
    val numbersMap = mapOf("key1" to 11, "key2" to 22, "key2" to 33, "key11" to 44)
    println(numbersMap)
    //基本的过滤函数是 filter()
    println(animals.filter { it.length > 3 })
    println(numbersMap.filter { (key, value) -> key.endsWith("1") && value > 22 })
    //如果想在过滤中使用元素在集合中的位置，应该使用 filterIndexed()
    println(animals.filterIndexed { index, s -> index != 0 && s.length < 4 })
    //如果想使用否定条件来过滤集合，请使用 filterNot()。它返回一个让谓词产生 false 的元素列表
    println(animals.filterNot { it.length == 3 })
    //还有一些函数能够通过过滤给定类型的元素来缩小元素的类型：
    //filterIsInstance() 返回给定类型的集合元素。在一个 List<Any> 上被调用时，filterIsInstance<T>()
    // 返回一个 List<T>，从而让你能够在集合元素上调用 T 类型的函数。
    val numbers = listOf(null, 1, "two", 3.0, "four")
    println("All String elements in upper case:")
    val strNums = numbers.filterIsInstance<String>()
    strNums.forEach {
        println(it.toUpperCase())
    }
    //filterNotNull() 返回所有的非空元素。在一个 List<T?> 上被调用时，filterNotNull() 返回一个 List<T: Any>，
    // 从而让你能够将所有元素视为非空对象
    val numbers2 = listOf(null, "one", "two", null)
    numbers2.filterNotNull().forEach {
        println("$it .len=${it.length}")   // 对可空的 String 来说长度不可用
    }
    //划分
    //另一个过滤函数 – partition() – 通过一个谓词过滤集合并且将不匹配的元素存放在一个单独的列表中。
    // 因此，你得到一个 List 的 Pair 作为返回值：第一个列表包含与谓词匹配的元素并且第二个列表包含原始集合中的所有其他元素
    val (match, rest) = animals.partition { it.length == 3 }
    println(match)
    println(rest)
    //检验谓词
//    如果至少有一个元素匹配给定谓词，那么 any() 返回 true。
//    如果没有元素与给定谓词匹配，那么 none() 返回 true。
//    如果所有元素都匹配给定谓词，那么 all() 返回 true。注意，在一个空集合上使用任何有效的谓词去调用 all() 都会返回 true 。
    println(animals.any { it.endsWith("g") })
    println(animals.none { it.endsWith("a") })
    println(animals.all { it.endsWith("g") })

    println(emptyList<Int>().all { it > 5 })   // vacuous truth

    //any() 和 none() 也可以不带谓词使用：在这种情况下它们只是用来检查集合是否为空。
    // 如果集合中有元素，any() 返回 true，否则返回 false；none() 则相反。
    val empty = emptyList<String>()

    println(numbers.any())
    println(empty.any())

    println(numbers.none())
    println(empty.none())

}

//九。加减操作符
fun testPlusMinus() {
    //在 Kotlin 中，为集合定义了 plus (+) 和 minus (-) 操作符。 它们把一个集合作为第一个操作数；
    // 第二个操作数可以是一个元素或者是另一个集合。 返回值是一个新的只读集合：
    val numbers = listOf("one", "two", "three", "four")
    val plusList = numbers + "five"
    val minusList = numbers - listOf("three", "four")
    println(plusList)
    println(minusList)
}

//十。分组
fun testGroup() {
    //Kotlin 标准库提供用于对集合元素进行分组的扩展函数。 基本函数 groupBy() 使用一个 lambda 函数并返回一个 Map。
    // 在此 Map 中，每个键都是 lambda 结果，而对应的值是返回此结果的元素 List。 例如，可以使用此函数将 String 列表按首字母分组。
    //
    //还可以使用第二个 lambda 参数（值转换函数）调用 groupBy()。 在带有两个 lambda 的 groupBy() 结果 Map 中，
    // 由 keySelector 函数生成的键映射到值转换函数的结果，而不是原始元素。
    val numbers = listOf("one", "two", "three", "four", "five", "six")

    println(numbers.groupBy { it.first().toUpperCase() })
    println(numbers.groupBy(keySelector = { it.first() }, valueTransform = { it.toUpperCase() }))
    //如果要对元素进行分组，然后一次将操作应用于所有分组，请使用 groupingBy() 函数。 它返回一个 Grouping 类型的实例。
    // 通过 Grouping 实例，可以以一种惰性的方式将操作应用于所有组：这些分组实际上是刚好在执行操作前构建的。
    //即，Grouping 支持以下操作：
    //eachCount() 计算每个组中的元素。
    //fold() 与 reduce() 对每个组分别执行 fold 与 reduce 操作，作为一个单独的集合并返回结果。
    //aggregate() 随后将给定操作应用于每个组中的所有元素并返回结果。 这是对 Grouping 执行任何操作的通用方法。
    // 当折叠或缩小不够时，可使用它来实现自定义操作。
    println(numbers.groupingBy { it.first() }.eachCount())
}

//十一。取集合的一部分
fun testPart() {
    val numbers = listOf("one", "two", "three", "four", "five", "six")
    //1. slice()
    // 返回具有给定索引的集合元素列表。 索引既可以是作为区间传入的也可以是作为整数值的集合传入的。
    println(numbers.slice(1..3))
    println(numbers.slice(0..4 step 2))
    println(numbers.slice(setOf(3, 4, 5)))
    //2。take() & drop()
    //要从头开始获取指定数量的元素，请使用 take() 函数。 要从尾开始获取指定数量的元素，请使用 takeLast()。
    // 当调用的数字大于集合的大小时，两个函数都将返回整个集合。
    //
    //要从头或从尾去除给定数量的元素，请调用 drop() 或 dropLast() 函数。
    println(numbers.take(3))
    println(numbers.takeLast(3))
    println(numbers.drop(1))
    println(numbers.dropLast(5))
    println(numbers.takeWhile { !it.startsWith('f') })
    println(numbers.takeLastWhile { it != "three" })
    println(numbers.dropWhile { it.length == 3 })
    println(numbers.dropLastWhile { it.contains('i') })
    //3. chunked()
    //要将集合分解为给定大小的“块”，请使用 chunked() 函数
    val numbers2 = (0..13).toList()
    println(numbers2.chunked(3))
    //还可以立即对返回的块应用转换
    println(numbers2.chunked(3) { it.sum() })  // `it` 为原始集合的一个块
    //4. windowed()
    //可以检索给定大小的集合元素中所有可能区间。 获取它们的函数称为 windowed()
    println(numbers.windowed(3))
    val nums = (1..11).toList()
    //partialWindows 包含从集合末尾的元素开始的较小的窗口。
    // 例如，如果请求三个元素的窗口，就不能为最后两个元素构建它们。在本例中，启用 partialWindows 将包括两个大小为2与1的列表。
    println(nums.windowed(3, step = 2, partialWindows = true))
    println(nums.windowed(3) { it.sum() })
    //要构建两个元素的窗口，有一个单独的函数——zipWithNext()。 它创建接收器集合的相邻元素对
    println(numbers.zipWithNext())
    println(numbers.zipWithNext() { s1, s2 -> s1.length > s2.length })
}

//十二。取单个元素
fun testGetOne() {
    //1. 按位置取
    //elementAt() 对于不提供索引访问或非静态已知提供索引访问的集合很有用。
    // 在使用 List 的情况下，使用索引访问操作符 （get() 或 []）更为习惯
    val numbers = linkedSetOf("one", "two", "three", "four", "five")
    println(numbers.elementAt(3))
    val numbersSortedSet = sortedSetOf("one", "two", "three", "four")
    println(numbersSortedSet.elementAt(0)) // 元素以升序存储
    println(numbers.first())
    println(numbers.last())
    println(numbers.elementAtOrNull(5))
    println(numbers.elementAtOrElse(5) { index -> "The value for index $index is undefined" })
    //2. 按条件取
    println(numbers.first { it.length > 3 })
    println(numbers.last { it.startsWith("f") })
    println(numbers.firstOrNull { it.length > 6 })
    println(numbers.lastOrNull { it.length > 6 })
    //或者，如果别名更适合你的情况，那么可以使用别名：
    //使用 find() 代替 firstOrNull()
    //使用 findLast() 代替 lastOrNull()
    val nums = listOf(1, 2, 3, 4)
    println(nums.find { it % 2 == 0 })
    println(nums.findLast { it % 2 == 0 })
    //3. 随机取元素
    println(numbers.random())
    //4. 检测存在与否
    println(numbers.contains("four"))
    println("zero" in numbers)
    println(numbers.containsAll(listOf("four", "two")))
    println(numbers.containsAll(listOf("one", "zero")))
    //可以通过调用 isEmpty() 和 isNotEmpty() 来检查集合中是否包含任何元素
    println(numbers.isEmpty())
    println(numbers.isNotEmpty())
    val empty = emptyList<String>()
    println(empty.isEmpty())
    println(empty.isNotEmpty())
}

//十三。集合排序
fun testShort() {
    //元素的顺序是某些集合类型的一个重要方面。 例如，如果拥有相同元素的两个列表的元素顺序不同，那么这两个列表也不相等。
    //1. 自然顺序:
    // 它是为 Comparable 接口的继承者定义的。 当没有指定其他顺序时，使用自然顺序为它们排序。
    println(Version(1, 2) > Version(1, 3))
    println(Version(2, 0) > Version(1, 5))
    //你可以为不可比较类型定义顺序，或者为可比较类型定义非自然顺序。 如需为类型定义自定义顺序，可以为其创建一个 Comparator。
    // Comparator 包含 compare() 函数：它接受一个类的两个实例并返回它们之间比较的整数结果。
    val lengthComparator = Comparator { str1: String, str2: String -> str1.length - str2.length }
    println(listOf("aaa", "bb", "c").sortedWith(lengthComparator))
    //定义一个 Comparator 的一种比较简短的方式是标准库中的 compareBy() 函数。 compareBy() 接受一个 lambda 表达式，
    // 该表达式从一个实例产生一个 Comparable 值，并将自定义顺序定义为生成值的自然顺序。 使用 compareBy()
    println(listOf("aaa", "bb", "c").sortedWith(compareBy { it.length }))
    //基本的函数 sorted() 和 sortedDescending() 返回集合的元素，这些元素按照其自然顺序升序和降序排序。 这些函数适用于 Comparable 元素的集合
    val numbers = mutableListOf("one", "two", "three", "four")
    println("Sorted ascending: ${numbers.sorted()}")
    println("Sorted descending: ${numbers.sortedDescending()}")
    //2. 自定义顺序
    //为了按照自定义顺序排序或者对不可比较对象排序，可以使用函数 sortedBy() 和 sortedByDescending()。
    // 它们接受一个将集合元素映射为 Comparable 值的选择器函数，并以该值的自然顺序对集合排序。
    val sortedNumbers = numbers.sortedBy { it.length }
    println("Sorted by length ascending: $sortedNumbers")
    val sortedByLast = numbers.sortedByDescending { it.last() }
    println("Sorted by the last letter descending: $sortedByLast")
    //如需为集合排序定义自定义顺序，可以提供自己的 Comparator。 为此，调用传入 Comparator 的 sortedWith() 函数。 使用此函数，按照字符串长度排序如下所示
    println("Sorted by length ascending: ${numbers.sortedWith(compareBy { it.length })}")
    //3. 倒序
    //reversed() 返回带有元素副本的新集合。 因此，如果你之后改变了原始集合，这并不会影响先前获得的 reversed() 的结果
    println(numbers.reversed())
    //asReversed()——返回相同集合实例的一个反向视图，因此，如果原始列表不会发生变化，那么它会比 reversed() 更轻量，更合适。
    val reversedNumbers = numbers.asReversed()
    println(reversedNumbers)
    //如果原始列表是可变的，那么其所有更改都会反映在其反向视图中，反之亦然。
    numbers.add("five")
    println(reversedNumbers)
    //4. 随机顺序
    //shuffled() 函数返回一个包含了以随机顺序排序的集合元素的新的 List。 你可以不带参数或者使用 Random 对象来调用它。
    println(numbers.shuffled())
    println(numbers.shuffled())
    println(numbers.shuffled())
}

//十四。集合聚合操作
fun testArithmetic() {
    //min() 与 max() 分别返回最小和最大的元素；
    //average() 返回数字集合中元素的平均值；
    //sum() 返回数字集合中元素的总和；
    //count() 返回集合中元素的数量；
    val numbers = listOf(6, 42, 10, 4)
    println("Count: ${numbers.count()}")
    println("Max: ${numbers.max()}")
    println("Min: ${numbers.min()}")
    println("Average: ${numbers.average()}")
    println("Sum: ${numbers.sum()}")
    //还有一些通过某些选择器函数或自定义 Comparator 来检索最小和最大元素的函数
    //maxBy()/minBy() 接受一个选择器函数并返回使选择器返回最大或最小值的元素。
    val min3Remainder = numbers.minBy { it % 3 }
    println(min3Remainder)
    //maxWith()/minWith() 接受一个 Comparator 对象并且根据此 Comparator 对象返回最大或最小元素。
    val strings = listOf("one", "two", "three", "four")
    val longestString = strings.maxWith(compareBy { it.length })
    println(longestString)
    //有一些高级的求和函数，它们接受一个函数并返回对所有元素调用此函数的返回值的总和：
    //sumBy() 使用对集合元素调用返回 Int 值的函数。
    //sumByDouble() 与返回 Double 的函数一起使用。
    println(numbers.sumBy { it * 2 })
    println(numbers.sumByDouble { it.toDouble() / 2 })
    //Fold 与 reduce
    //这两个函数的区别在于：fold() 接受一个初始值并将其用作第一步的累积值，而 reduce() 的第一步则将第一个和第二个元素作为第一步的操作参数。
    val sum = numbers.reduce { sum, element -> sum + element * 2 }
    println(sum)
    val sumDoubled = numbers.fold(0) { sum, element -> sum + element * 2 }
    println(sumDoubled)
    //val sumDoubledReduce = numbers.reduce { sum, element -> sum + element * 2 } //错误：第一个元素在结果中没有加倍
    //println(sumDoubledReduce)
    //如需将函数以相反的顺序应用于元素，可以使用函数 reduceRight() 和 foldRight() 它们的工作方式
    // 类似于 fold() 和 reduce()，但从最后一个元素开始，然后再继续到前一个元素。 记住，在使用 foldRight
    // 或 reduceRight 时，操作参数会更改其顺序：第一个参数变为元素，然后第二个参数变为累积值。
    val sumDoubledRight = numbers.foldRight(0) { element, sum -> sum + element * 2 }
    println(sumDoubledRight)
    //你还可以使用将元素索引作为参数的操作。 为此，使用函数 reduceIndexed() 和 foldIndexed() 传递元素索引作为操作的第一个参数。
    //还有将这些操作从右到左应用于集合元素的函数——reduceRightIndexed() 与 foldRightIndexed()。
    val sumEven =
        numbers.foldIndexed(0) { idx, sum, element -> if (idx % 2 == 0) sum + element else sum }
    println(sumEven)
    val sumEvenRight =
        numbers.foldRightIndexed(0) { idx, element, sum -> if (idx % 2 == 0) sum + element else sum }
    println(sumEvenRight)
}

//十五。集合写操作
fun testWrite(){
    //1. 添加元素
    //add() 函数。将指定的单个对象添加到集合的末尾
    val numbers = mutableListOf(1, 2, 3, 4)
    numbers.add(5)
    println(numbers)
    //将参数对象的每个元素添加到列表或集合中
    numbers.addAll(arrayOf(7, 8))
    println(numbers)
    //也可以调用 addAll() 时指定一个元素位置作为第一参数
    numbers.addAll(2, setOf(3, 4))
    println(numbers)
    //还可以使用 plus 运算符 - plusAssign (+=) 添加元素
    val numbers2 = mutableListOf("one", "two")
    numbers2 += "three"
    println(numbers2)
    numbers2 += listOf("four", "five")
    println(numbers2)
    //2. 删除元素
    //remove() 接受元素值，并删除该值的一个匹配项
    val numbers3 = mutableListOf(1, 2, 3, 4, 3)
    numbers3.remove(3)                    // 删除了第一个 `3`
    println(numbers3)
    numbers3.remove(5)                    // 什么都没删除
    println(numbers3)
    //removeAll() 移除参数集合中存在的所有元素。 或者，你可以用谓词作为参数来调用它；在这种情况下，函数移除谓词产生 true 的所有元素
    //retainAll() 与 removeAll() 相反：它移除除参数集合中的元素之外的所有元素。 当与谓词一起使用时，它只留下与之匹配的元素
    //clear() 从列表中移除所有元素并将其置空
    println(numbers3)
    numbers3.retainAll { it >= 3 }
    println(numbers3)
    numbers3.clear()
    println(numbers3)

    val numbersSet = mutableSetOf("one", "two", "three", "four")
    numbersSet.removeAll(setOf("one", "two"))
    println(numbersSet)
    //从集合中移除元素的另一种方法是使用 minusAssign (-=)
    val numbers4 = mutableListOf("one", "two", "three", "three", "four")
    numbers4 -= "three"
    println(numbers4)
    numbers4 -= listOf("four", "five")
    //numbers4 -= listOf("four")    // 与上述相同
    println(numbers4)
}

//十六。List 相关操作
fun testList1(){
    //1. 按索引取元素
    val numbers = listOf(1, 2, 3, 4)
    println(numbers.get(0))
    println(numbers[0])
    //numbers.get(5)                         // exception!
    println(numbers.getOrNull(5))             // null
    //getOrElse() 提供用于计算默认值的函数，如果集合中不存在索引，则返回默认值。
    println(numbers.getOrElse(5, {it}))        // 5
    //2. 取列表的一部分
    val numbers2 = (0..13).toList()
    println(numbers2.subList(3, 6))
    //3. 查找元素位置
    val numbers3 = listOf(1, 2, 3, 4, 2, 5)
    println(numbers3.indexOf(2))
    println(numbers3.lastIndexOf(2))
    println(numbers.indexOfFirst { it > 2})
    println(numbers.indexOfLast { it % 2 == 1})
    //在有序列表中二分查找
    val numbers4 = mutableListOf("one", "two", "three", "four")
    numbers4.sort()
    println(numbers4)
    println(numbers4.binarySearch("two"))  // 3
    println(numbers4.binarySearch("z")) // -5
    println(numbers4.binarySearch("two", 0, 2))  // -3
    //Comparator 二分搜索
    data class Product(val name: String, val price: Double)
    val productList = listOf(
        Product("WebStorm", 49.0),
        Product("AppCode", 99.0),
        Product("DotTrace", 129.0),
        Product("ReSharper", 149.0))
    println(productList.binarySearch(Product("AppCode", 99.0), compareBy<Product> { it.price }.thenBy { it.name }))
    val colors = listOf("Blue", "green", "ORANGE", "Red", "yellow")
    println(colors.binarySearch("RED", String.CASE_INSENSITIVE_ORDER)) // 3
    //比较函数二分搜索
    fun priceComparison(product: Product, price: Double) = sign(product.price - price).toInt()
    println(productList.binarySearch { priceComparison(it, 99.0) })
    //4. List 写操作
    val numbers5 = mutableListOf("one", "five", "six")
    numbers5.add(1, "two")
    numbers5.addAll(2, listOf("three", "four"))
    println(numbers5)
    numbers5[1] =  "two"
    println(numbers5)
    val numbers6 = mutableListOf(1, 2, 3, 4)
    numbers6.fill(3)
    println(numbers6)
    numbers6.removeAt(1)
    println(numbers6)
   //排序
    val numbers7 = mutableListOf("one", "two", "three", "four")

    numbers7.sort()
    println("Sort into ascending: $numbers7")
    numbers7.sortDescending()
    println("Sort into descending: $numbers7")

    numbers7.sortBy { it.length }
    println("Sort into ascending by length: $numbers7")
    numbers7.sortByDescending { it.last() }
    println("Sort into descending by the last letter: $numbers7")

    numbers7.sortWith(compareBy<String> { it.length }.thenBy { it })
    println("Sort by Comparator: $numbers7")

    numbers7.shuffle()
    println("Shuffle: $numbers7")

    numbers7.reverse()
    println("Reverse: $numbers7")

    //Set 相关操作
    val numbersSet = setOf("one", "two", "three")

    //要将两个集合合并为一个（并集），可使用 union() 函数
    println(numbersSet union setOf("four", "five"))
    println(setOf("four", "five") union numbersSet)
    //要查找两个集合中都存在的元素（交集），请使用 intersect() 。
    println(numbersSet intersect setOf("two", "one"))
    //要查找另一个集合中不存在的集合元素（差集），请使用 subtract()
    println(numbersSet subtract setOf("three", "four"))
    println(numbersSet subtract setOf("four", "three")) // 相同的输出
}

//十七。Map相关操作
fun testMap11(){
    val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3,"key11" to 11)
    println(numbersMap.get("one"))
    println(numbersMap["one"])
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        println(numbersMap.getOrDefault("four", 10))
    }
    println(numbersMap["five"])               // null
    //numbersMap.getValue("six")      // exception!
    //keys 是 Map 中所有键的集合， values 是 Map 中所有值的集合
    println(numbersMap.keys)
    println(numbersMap.values)
    //过滤
    val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10}
    println(filteredMap)
    //还有两种用于过滤 map 的特定函数：按键或按值。 这两种方式，都有对应的函数： filterKeys() 和 filterValues() 。
    val filteredKeysMap = numbersMap.filterKeys { it.endsWith("1") }
    val filteredValuesMap = numbersMap.filterValues { it < 10 }
    println(filteredKeysMap)
    println(filteredValuesMap)
    //plus 与 minus 操作
    println(numbersMap + Pair("four", 4))
    println(numbersMap + Pair("one", 10))
    println(numbersMap + mapOf("five" to 5, "one" to 11))
    println(numbersMap - "one")
    println(numbersMap - listOf("two", "four"))
    //添加与更新条目
    numbersMap.put("key22", 22)
    println(numbersMap)
    //如果给定键已存在于 Map 中，则 put() 与 putAll() 都将覆盖值。 因此，可以使用它们来更新 Map 条目的值。
    val previousValue = numbersMap.put("one", 11)
    println("value associated with 'one', before: $previousValue, after: ${numbersMap["one"]}")
    println(numbersMap)
    //还可以使用快速操作符将新条目添加到 Map 。 有两种方式：
    //1.plusAssign （+=） 操作符。
    //2.[] 操作符为 put() 的别名。
    numbersMap["three"] = 3     // 调用 numbersMap.put("three", 3)
    numbersMap += mapOf("four" to 4, "five" to 5)
    println(numbersMap)
    //删除条目
    numbersMap.remove("one")
    println(numbersMap)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        numbersMap.remove("three", 4)
    } //不会删除任何条目
    println(numbersMap)
    numbersMap.keys.remove("one")
    println(numbersMap)
    numbersMap.values.remove(3)
    println(numbersMap)
    //minusAssign （-=） 操作符也可用于可变 Map
    numbersMap -= "two"
    println(numbersMap)
    numbersMap -= "five" //不会删除任何条目
    println(numbersMap)
}

